#ifndef __BLOCK_MATH_IMPL_H__
#define __BLOCK_MATH_IMPL_H__



template<typename T, int N>
class Vector_T;
template<typename T>
class Matrix4_T;


template <typename T, int N>
struct dot_impl
{
    static T Do(T const * lhs, T const * rhs)
    {
        return lhs[0] * rhs[0] + dot_impl<T, N - 1>::Do(lhs + 1, rhs + 1);
    }
};

template<typename T>
struct dot_impl<T, 1>
{
    static T Do(T const * lhs, T const * rhs)
    {
        return lhs[0] * rhs[0];
    }
};



template<typename T, int N>
struct transform_impl
{
    static Vector_T<T, 4> Do(Vector_T<T, N> const & v, Matrix4_T<T> const & mat);
};

template<typename T>
struct transform_impl<T, 4>
{
    static Vector_T<T, 4> Do(Vector_T<T, 4> const & v, Matrix4_T<T> const & mat)
    {
        return Vector_T<T, 4>(v.x() * mat(0, 0) + v.y() * mat(1, 0) + v.z() * mat(2, 0) + v.w() * mat(3, 0),
                v.x() * mat(0, 1) + v.y() * mat(1, 1) + v.z() * mat(2, 1) + v.w() * mat(3, 1),
                v.x() * mat(0, 2) + v.y() * mat(1, 2) + v.z() * mat(2, 2) + v.w() * mat(3, 2),
                v.x() * mat(0, 3) + v.y() * mat(1, 3) + v.z() * mat(2, 3) + v.w() * mat(3, 3));
    }
};

template<typename T>
struct transform_impl<T, 3>
{
    static Vector_T<T, 4> Do(Vector_T<T, 3> const & v, Matrix4_T<T> const & mat)
    {
        return Vector_T<T, 4>(v.x() * mat(0, 0) + v.y() * mat(1, 0) + v.z() * mat(2, 0) + mat(3, 0),
                v.x() * mat(0, 1) + v.y() * mat(1, 1) + v.z() * mat(2, 1) + mat(3, 1),
                v.x() * mat(0, 2) + v.y() * mat(1, 2) + v.z() * mat(2, 2) + mat(3, 2),
                v.x() * mat(0, 3) + v.y() * mat(1, 3) + v.z() * mat(2, 3) + mat(3, 3));
    }
};

template<typename T>
struct transform_impl<T, 2>
{
    static Vector_T<T, 4> Do(Vector_T<T, 2> const & v, Matrix4_T<T> const & mat)
    {
        return Vector_T<T, 4>(v.x() * mat(0, 0) + v.y() * mat(1, 0) + mat(3, 0),
                v.x() * mat(0, 1) + v.y() * mat(1, 1) + mat(3, 1),
                v.x() * mat(0, 2) + v.y() * mat(1, 2) + mat(3, 2),
                v.x() * mat(0, 3) + v.y() * mat(1, 3) + mat(3, 3));
    }
};



#endif
